package cn.edu.dgut.css.sai.security.oauth2.core.http.converter;

import cn.edu.dgut.css.sai.security.oauth2.client.endpoint.SaiCommonOAuth2AccessTokenResponseClient;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;

import java.util.Map;
import java.util.stream.Collectors;

/**
 * 重写{@link OAuth2AccessTokenResponseHttpMessageConverter} , 如果参数没有 "token_type" 的话，则增加 token_type=Bearer 。
 * <p>
 *
 * @author sai
 * @see SaiCommonOAuth2AccessTokenResponseClient
 * @see OAuth2AccessTokenResponseHttpMessageConverter
 * @see OAuth2ParameterNames
 * @since 2.0
 */
public final class SaiCommonOAuth2AccessTokenResponseHttpMessageConverter extends OAuth2AccessTokenResponseHttpMessageConverter {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected OAuth2AccessTokenResponse readInternal(Class<? extends OAuth2AccessTokenResponse> clazz, HttpInputMessage inputMessage) throws HttpMessageNotReadableException {

        try {
            Map<String, Object> tokenResponseParameters = objectMapper.readValue(inputMessage.getBody(), new TypeReference<>() {
            });

            if (!tokenResponseParameters.containsKey(OAuth2ParameterNames.TOKEN_TYPE))
                tokenResponseParameters.put(OAuth2ParameterNames.TOKEN_TYPE, OAuth2AccessToken.TokenType.BEARER.getValue());

            return this.tokenResponseConverter.convert(
                    tokenResponseParameters.entrySet().stream()
                            .collect(Collectors.toMap(
                                    Map.Entry::getKey,
                                    entry -> String.valueOf(entry.getValue()))));
        } catch (Exception ex) {
            throw new HttpMessageNotReadableException("An error occurred reading the OAuth 2.0 Access Token Response: " +
                    ex.getMessage(), ex, inputMessage);
        }
    }
}
